`include "defines.d"
`define ID .router_id_x(router_id_x), .router_id_y(router_id_y)
module router
       //inputs are follows
       (	
       	clock, reset,
       	data_to_queue_e, data_to_queue_s, data_to_queue_w, data_to_queue_n, data_to_queue_h, 
       	valid_to_queue_e, valid_to_queue_s, valid_to_queue_w, valid_to_queue_n, valid_to_queue_h, 
       	credits_to_om_e, credits_to_om_s, credits_to_om_w, credits_to_om_n, credits_to_om_h,
       	
       //outputs are as follows
       data_from_om_e, data_from_om_s, data_from_om_n, data_from_om_w, data_from_om_h, 
       valid_from_om_e, valid_from_om_s, valid_from_om_n, valid_from_om_w, valid_from_om_h,
       
       credits_from_queue_e, credits_from_queue_s,credits_from_queue_w,credits_from_queue_n,credits_from_queue_h
     		);
       parameter [2:0] router_id_x = 3'b000;
       parameter [2:0] router_id_y = 3'b000;
       
       input wire clock, reset;
       //************************************ input queues ******************************************
       input [`DATA_WIDTH-1:0] 	data_to_queue_e, data_to_queue_s, data_to_queue_w, data_to_queue_n, data_to_queue_h;
       input 							valid_to_queue_e, valid_to_queue_s, valid_to_queue_w, valid_to_queue_n, valid_to_queue_h; 
       wire [`DATA_WIDTH-1:0]		d_from_IQE, d_from_IQS, d_from_IQW, d_from_IQN, d_from_IQH;
       wire 							v_from_IQE, v_from_IQS, v_from_IQW, v_from_IQN, v_from_IQH;
       wire								IQE_ready_from_CTRL, IQS_ready_from_CTRL, IQW_ready_from_CTRL, IQN_ready_from_CTRL, IQH_ready_from_CTRL;
       output wire 					credits_from_queue_e, credits_from_queue_s, credits_from_queue_w ,credits_from_queue_n, credits_from_queue_h;

       queue IQE (.clock(clock), .reset(reset), .i_d(data_to_queue_e), .i_v(valid_to_queue_e), .credits_back(credits_from_queue_e), .o_d(d_from_IQE), .o_v(v_from_IQE), .o_r(IQE_ready_from_CTRL));
       queue IQS (.clock(clock), .reset(reset), .i_d(data_to_queue_s), .i_v(valid_to_queue_s), .credits_back(credits_from_queue_s), .o_d(d_from_IQS), .o_v(v_from_IQS), .o_r(IQS_ready_from_CTRL));
       queue IQW (.clock(clock), .reset(reset), .i_d(data_to_queue_w), .i_v(valid_to_queue_w), .credits_back(credits_from_queue_w), .o_d(d_from_IQW), .o_v(v_from_IQW), .o_r(IQW_ready_from_CTRL));
       queue IQN (.clock(clock), .reset(reset), .i_d(data_to_queue_n), .i_v(valid_to_queue_n), .credits_back(credits_from_queue_n), .o_d(d_from_IQN), .o_v(v_from_IQN), .o_r(IQN_ready_from_CTRL));
       queue IQH (.clock(clock), .reset(reset), .i_d(data_to_queue_h), .i_v(valid_to_queue_h), .credits_back(credits_from_queue_h), .o_d(d_from_IQH), .o_v(v_from_IQH), .o_r(IQH_ready_from_CTRL));

       //******************************************** CONTROL LOGIC ******************************************************'
       wire ready_from_om_e, ready_from_om_s, ready_from_om_w, ready_from_om_n, ready_from_om_h;
       wire [2:0] select_for_om_e, select_for_om_s, select_for_om_w, select_for_om_n, select_for_om_h;
       control #(`ID) CTRL (.clock(clock), .reset(reset),
                       			.dest_e(d_from_IQE[`DESTINATION]), .dest_s(d_from_IQS[`DESTINATION]), .dest_w(d_from_IQW[`DESTINATION]), .dest_n(d_from_IQN[`DESTINATION]), .dest_h(d_from_IQH[`DESTINATION]),
										.type_e(d_from_IQE[`TYPE]), .type_s(d_from_IQS[`TYPE]), .type_w(d_from_IQW[`TYPE]), .type_n(d_from_IQN[`TYPE]), .type_h(d_from_IQH[`TYPE]),
										.valid_e(v_from_IQE), .valid_s(v_from_IQS), .valid_w(v_from_IQW), .valid_n(v_from_IQN), .valid_h(v_from_IQH),
										.om_ready_e(ready_from_om_e), .om_ready_s(ready_from_om_s), .om_ready_w(ready_from_om_w), .om_ready_n(ready_from_om_n), .om_ready_h(ready_from_om_h),
										.q_ready_e(IQE_ready_from_CTRL), .q_ready_s(IQS_ready_from_CTRL), .q_ready_w(IQW_ready_from_CTRL), .q_ready_n(IQN_ready_from_CTRL), .q_ready_h(IQH_ready_from_CTRL),
										.sel_e(select_for_om_e), .sel_s(select_for_om_s), .sel_w(select_for_om_w), .sel_n(select_for_om_n), .sel_h(select_for_om_h)
                       );

       //*************************************************CROSSBAR******************************************************************
       wire v_xbar_to_om_e, v_xbar_to_om_s, v_xbar_to_om_w, v_xbar_to_om_n, v_xbar_to_om_h;
       wire [`DATA_WIDTH-1:0] d_xbar_to_om_e, d_xbar_to_om_s, d_xbar_to_om_w, d_xbar_to_om_n, d_xbar_to_om_h;
       xbar CROSSBAR(
       	.eastIn({v_from_IQE,d_from_IQE}),
       	.westIn({v_from_IQW,d_from_IQW}), 
       	.southIn({v_from_IQS,d_from_IQS}),
       	.northIn({v_from_IQN,d_from_IQN}),
       	.hereIn({v_from_IQH,d_from_IQH}),
       	
       	.arbitEast(select_for_om_e), .arbitWest(select_for_om_w), .arbitSouth(select_for_om_s), .arbitNorth(select_for_om_n), .arbitHere(select_for_om_h),
       	
			.eastOut({v_xbar_to_om_e, d_xbar_to_om_e}), 
			.southOut({v_xbar_to_om_s, d_xbar_to_om_s}), 
			.westOut({v_xbar_to_om_w,d_xbar_to_om_w}), 
			.northOut({v_xbar_to_om_n, d_xbar_to_om_n}),
			.hereOut({v_xbar_to_om_h, d_xbar_to_om_h})
       );

       //********************************************** OUTPUT MODULES *************************************************************
		output wire [`DATA_WIDTH-1:0] data_from_om_e, data_from_om_s, data_from_om_w, data_from_om_n, data_from_om_h;
		input wire credits_to_om_e, credits_to_om_s, credits_to_om_w, credits_to_om_n,credits_to_om_h;
		output wire valid_from_om_e, valid_from_om_s, valid_from_om_w, valid_from_om_n, valid_from_om_h;
		output_module OME (.clock(clock), .reset(reset),
       							.data_out(data_from_om_e), .credit_in(credits_to_om_e), .valid_out(valid_from_om_e), .source_valid(v_xbar_to_om_e), .data_from_source(d_xbar_to_om_e), .ready_to_source(ready_from_om_e)
       						);

		output_module OMS (.clock(clock),.reset(reset), 
       							.data_out(data_from_om_s), .credit_in(credits_to_om_s), .valid_out(valid_from_om_s), .source_valid(v_xbar_to_om_s), .data_from_source(d_xbar_to_om_s), .ready_to_source(ready_from_om_s)
       						);

		output_module OMW (.clock(clock), .reset(reset),
       							.data_out(data_from_om_w), .credit_in(credits_to_om_w), .valid_out(valid_from_om_w), .source_valid(v_xbar_to_om_w), .data_from_source(d_xbar_to_om_w), .ready_to_source(ready_from_om_w)
       						);

		output_module OMN (.clock(clock), .reset(reset),
       							.data_out(data_from_om_n), .credit_in(credits_to_om_n), .valid_out(valid_from_om_n), .source_valid(v_xbar_to_om_n), .data_from_source(d_xbar_to_om_n), .ready_to_source(ready_from_om_n)
       						);

		output_module OMH (.clock(clock),  .reset(reset),
       							.data_out(data_from_om_h), .credit_in(credits_to_om_h), .valid_out(valid_from_om_h), .source_valid(v_xbar_to_om_h), .data_from_source(d_xbar_to_om_h), .ready_to_source(ready_from_om_h)
       						);
endmodule
